home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / network / ka9q / nhclb120.zoo / slhc.c < prev    next >
C/C++ Source or Header  |  1992-06-18  |  15KB  |  611 lines

  1. /*
  2.  * Routines to compress and uncompress tcp packets (for transmission
  3.  * over low speed serial lines).
  4.  *
  5.  * Copyright (c) 1989 Regents of the University of California.
  6.  * All rights reserved.
  7.  *
  8.  * Redistribution and use in source and binary forms are permitted
  9.  * provided that the above copyright notice and this paragraph are
  10.  * duplicated in all such forms and that any documentation,
  11.  * advertising materials, and other materials related to such
  12.  * distribution and use acknowledge that the software was developed
  13.  * by the University of California, Berkeley.  The name of the
  14.  * University may not be used to endorse or promote products derived
  15.  * from this software without specific prior written permission.
  16.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  17.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  18.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  19.  *
  20.  *    Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
  21.  *    - Initial distribution.
  22.  *
  23.  *
  24.  * modified for KA9Q Internet Software Package by
  25.  * Katie Stevens (dkstevens@ucdavis.edu)
  26.  * University of California, Davis
  27.  * Computing Services
  28.  *    - 01-31-90    initial adaptation (from 1.19)
  29.  *    PPP.05    02-15-90 [ks]
  30.  *    PPP.08    05-02-90 [ks]    use PPP protocol field to signal compression
  31.  *    PPP.15    09-90     [ks]    improve mbuf handling
  32.  *    PPP.16    11-02     [karn]    substantially rewritten to use NOS facilities
  33.  *
  34.  *    - Feb 1991    Bill_Simpson@um.cc.umich.edu
  35.  *            variable number of conversation slots
  36.  *            allow zero or one slots
  37.  *            separate routines
  38.  *            status display
  39.  */
  40. #if !defined(MWC)
  41. #include <memory.h>
  42. #else
  43. int memcpy(),memcmp();
  44. void memset();
  45. #endif
  46. #include "global.h"
  47. #include "mbuf.h"
  48. #include "timer.h"
  49. #include "internet.h"
  50. #include "netuser.h"
  51. #include "ip.h"
  52. #include "tcp.h"
  53. #include "slhc.h"
  54.  
  55. struct mbuf *htonip();
  56. struct mbuf *htontcp();
  57. #define __ARGS(x) x
  58.  
  59. extern int last_retran;
  60. #ifndef ATARI_ST
  61. static char *encode __ARGS((char *cp,int n));
  62. static long decode __ARGS((struct mbuf **bpp));
  63. #else
  64. static char *encode();
  65. static long decode();
  66. #endif
  67.  
  68. #define    PULLCHAR(bpp)\
  69.  ((bpp) != NULL && (*bpp) != NULLBUF && (*bpp)->cnt > 1 ? \
  70.  ((*bpp)->cnt--,(unsigned char)*(*bpp)->data++) : pullchar(bpp))
  71.  
  72. /* Initialize compression data structure
  73.  *    slots must be in range 0 to 255 (zero meaning no compression)
  74.  */
  75. struct slcompress *
  76. slhc_init( rslots, tslots )
  77. int rslots;
  78. int tslots;
  79. {
  80.     register int16 i;
  81.     register struct cstate *ts;
  82.     struct slcompress *comp;
  83.  
  84.     comp = (struct slcompress *)calloc(1, sizeof(struct slcompress) );
  85.     if (! comp)
  86.         return NULL;
  87.  
  88.     if ( rslots > 0  &&  rslots < 256 ) {
  89.         comp->rstate =
  90.           (struct cstate *)calloc(rslots, sizeof(struct cstate) );
  91.         if (! comp->rstate)
  92.             return NULL;
  93.         comp->rslot_limit = rslots - 1;
  94.     }
  95.  
  96.     if ( tslots > 0  &&  tslots < 256 ) {
  97.         comp->tstate = 
  98.           (struct cstate *)calloc(tslots, sizeof(struct cstate) );
  99.         if (! comp->tstate)
  100.             return NULL;
  101.         comp->tslot_limit = tslots - 1;
  102.     }
  103.  
  104.     comp->xmit_oldest = 0;
  105.     comp->xmit_current = 255;
  106.     comp->recv_current = 255;
  107.     /*
  108.      * don't accept any packets with implicit index until we get
  109.      * one with an explicit index.  Otherwise the uncompress code
  110.      * will try to use connection 255, which is almost certainly
  111.      * out of range
  112.      */
  113.     comp->flags |= SLF_TOSS;
  114.  
  115.     if ( tslots > 0 ) {
  116.         ts = comp->tstate;
  117.         for(i = comp->tslot_limit; i > 0; --i){
  118.             ts[i].this = i;
  119.             ts[i].next = &(ts[i - 1]);
  120.         }
  121.         ts[0].next = &(ts[comp->tslot_limit]);
  122.         ts[0].this = 0;
  123.     }
  124.     return comp;
  125. }
  126.  
  127.  
  128. /* Free a compression data structure */
  129. void
  130. slhc_free(comp)
  131. struct slcompress *comp;
  132. {
  133.     if ( comp == NULLSLCOMPR )
  134.         return;
  135.  
  136.     if ( comp->rstate != NULLSLSTATE )
  137.         free( comp->rstate );
  138.  
  139.     if ( comp->tstate != NULLSLSTATE )
  140.         free( comp->tstate );
  141.  
  142.     free( comp );
  143. }
  144.  
  145.  
  146. /* Encode a number */
  147. static char *
  148. encode(cp,n)
  149. register char *cp;
  150. int n;
  151. {
  152.     if(n >= 256 || n == 0){
  153.         *cp++ = 0;
  154.         cp = put16(cp,n);
  155.     } else {
  156.         *cp++ = n;
  157.     }
  158.     return cp;
  159. }
  160.  
  161. /* Decode a number */
  162. static long
  163. decode(bpp)
  164. struct mbuf **bpp;
  165. {
  166.     register int x;
  167.  
  168.     x = PULLCHAR(bpp);
  169.     if(x == 0){
  170.         return pull16(bpp) & 0xffff;    /* pull16 returns -1 on error */
  171.     } else {
  172.         return x & 0xff;        /* -1 if PULLCHAR returned error */
  173.     }
  174. }
  175.  
  176. int
  177. slhc_compress(comp, bpp, compress_cid)
  178. struct slcompress *comp;
  179. struct mbuf **bpp;
  180. int compress_cid;
  181. {
  182.     register struct cstate *ocs = &(comp->tstate[comp->xmit_oldest]);
  183.     register struct cstate *lcs = ocs;
  184.     register struct cstate *cs = lcs->next;
  185.     register int16 hlen;
  186.     register struct tcp *oth;
  187.     register unsigned long deltaS, deltaA;
  188.     register int16 changes = 0;
  189.     char new_seq[16];
  190.     register char *cp = new_seq;
  191.     struct mbuf *bp;
  192.     struct tcp th;
  193.     struct ip iph;
  194.  
  195.     /* Extract IP header */
  196.     hlen = ntohip(&iph,bpp);
  197.  
  198.     /* Bail if this packet isn't TCP, or is an IP fragment */
  199.     if(iph.protocol != TCP_PTCL || (iph.fl_offs & F_OFFSET) != 0 || 
  200.                        (iph.fl_offs & MF)){
  201.         /* Send as regular IP */
  202.         if(iph.protocol != TCP_PTCL)
  203.             comp->sls_o_nontcp++;
  204.         else
  205.             comp->sls_o_tcp++;
  206.         *bpp = htonip(&iph,*bpp,iph.checksum);
  207.         return SL_TYPE_IP;
  208.     }
  209.     /* Extract TCP header */
  210.     hlen += ntohtcp(&th,bpp);
  211.  
  212.     /*  Bail if the TCP packet isn't `compressible' (i.e., ACK isn't set or
  213.      *  some other control bit is set).
  214.      */
  215.     if((th.flags & SYN) || (th.flags & FIN) || (th.flags & RST) ||
  216.         ! (th.flags & ACK)){
  217.         /* TCP connection stuff; send as regular IP */
  218.         comp->sls_o_tcp++;
  219.         *bpp = htontcp(&th,*bpp,NULL);
  220.         *bpp = htonip(&iph,*bpp,iph.checksum);
  221.         return SL_TYPE_IP;
  222.     }
  223.     /*
  224.      * Packet is compressible -- we're going to send either a
  225.      * COMPRESSED_TCP or UNCOMPRESSED_TCP packet.  Either way,
  226.      * we need to locate (or create) the connection state.
  227.      *
  228.      * States are kept in a circularly linked list with
  229.      * xmit_oldest pointing to the end of the list.  The
  230.      * list is kept in lru order by moving a state to the
  231.      * head of the list whenever it is referenced.  Since
  232.      * the list is short and, empirically, the connection
  233.      * we want is almost always near the front, we locate
  234.      * states via linear search.  If we don't find a state
  235.      * for the datagram, the oldest state is (re-)used.
  236.      */
  237.     for ( ; ; ) {
  238.         if( iph.source == cs->cs_ip.source
  239.          && iph.dest == cs->cs_ip.dest
  240.          && th.source == cs->cs_tcp.source
  241.          && th.dest == cs->cs_tcp.dest)
  242.             goto found;
  243.  
  244.         /* if current equal oldest, at end of list */
  245.         if ( cs == ocs )
  246.             break;
  247.         lcs = cs;
  248.         cs = cs->next;
  249.         comp->sls_o_searches++;
  250.     };
  251.     /*
  252.      * Didn't find it -- re-use oldest cstate.  Send an
  253.      * uncompressed packet that tells the other side what
  254.      * connection number we're using for this conversation.
  255.      *
  256.      * Note that since the state list is circular, the oldest
  257.      * state points to the newest and we only need to set
  258.      * xmit_oldest to update the lru linkage.
  259.      */
  260.     comp->sls_o_misses++;
  261.     comp->xmit_oldest = lcs->this;
  262.  
  263.     goto uncompressed;
  264.  
  265. found:
  266.     /*
  267.      * Found it -- move to the front on the connection list.
  268.      */
  269.     if(lcs == ocs) {
  270.         /* found at most recently used */
  271.     } else if (cs == ocs) {
  272.         /* found at least recently used */
  273.         comp->xmit_oldest = lcs->this;
  274.     } else {
  275.         /* more than 2 elements */
  276.         lcs->next = cs->next;
  277.         cs->next = ocs->next;
  278.         ocs->next = cs;
  279.     }
  280.  
  281.     /*
  282.      * Make sure that only what we expect to change changed.
  283.      * Check the following:
  284.      * IP protocol version, header length & type of service.
  285.      * The "Don't fragment" bit.
  286.      * The time-to-live field.
  287.      * The TCP header length.
  288.      * IP options, if any.
  289.      * TCP options, if any.
  290.      * If any of these things are different between the previous &
  291.      * current datagram, we send the current datagram `uncompressed'.
  292.      */
  293.     oth = &cs->cs_tcp;
  294.  
  295.     if(last_retran
  296.      || iph.version != cs->cs_ip.version || iph.optlen != cs->cs_ip.optlen
  297.      || iph.tos != cs->cs_ip.tos
  298.      || (iph.fl_offs & DF) != (cs->cs_ip.fl_offs & DF)
  299.      || iph.ttl != cs->cs_ip.ttl
  300.      || th.optlen != cs->cs_tcp.optlen
  301.      || (iph.optlen > 0 && memcmp(iph.options,cs->cs_ip.options,iph.optlen) != 0)
  302.      || (th.optlen > 0 && memcmp(th.options,cs->cs_tcp.options,th.optlen) != 0)){
  303.           last_retran = 0;
  304.         goto uncompressed;
  305.     }
  306.     /*
  307.      * Figure out which of the changing fields changed.  The
  308.      * receiver expects changes in the order: urgent, window,
  309.      * ack, seq (the order minimize